/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolóxico de Galicia
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.libreplan.web.common;

import static org.libreplan.web.I18nHelper._;

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.daos.IEntitySequenceDAO;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Base class for all model which manage code sequences.
 * @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
 */
public abstract class IntegrationEntityModel implements IIntegrationEntityModel {

    @Autowired
    private IEntitySequenceDAO entitySequenceDAO;

    private String oldCode;

    private Map<IntegrationEntity, String> oldCodesChildren = new HashMap<IntegrationEntity, String>();

    private Boolean generateCodeOld;

    public abstract EntityNameEnum getEntityName();

    public abstract IntegrationEntity getCurrentEntity();

    protected abstract Set<IntegrationEntity> getChildren();

    protected void initOldCodes() {
        oldCodesChildren.clear();
        if (getCurrentEntity() != null) {
            setOldCode(getCurrentEntity().getCode());
            for (IntegrationEntity child : getChildren()) {
                oldCodesChildren.put(child, child.getCode());
            }
            setGenerateCodeOld(getCurrentEntity().isCodeAutogenerated());
        }
    }

    protected void restoreOldCodes() {
        getCurrentEntity().setCode(getOldCode());
        for (IntegrationEntity child : oldCodesChildren.keySet()) {
            child.setCode(oldCodesChildren.get(child));
        }
    }

    protected void setDefaultCode() throws ConcurrentModificationException {
        String code = getEntitySequenceDAO().getNextEntityCode(getEntityName());
        if (code == null) {
            throw new ConcurrentModificationException(
                    _("Could not retrieve Code. Please, try again later"));
        }
        getCurrentEntity().setCode(code);
    }

    protected Integer getNumberOfDigitsCode() {
        return entitySequenceDAO.getNumberOfDigitsCode(getEntityName());
    }

    @Override
    public void setCodeAutogenerated(boolean codeAutogenerated)
            throws ConcurrentModificationException {
        if (getCurrentEntity() != null) {
            if (codeAutogenerated) {
                if (getCurrentEntity().isNewObject()) {
                    setDefaultCode();
                } else {
                    if (this.isGenerateCodeOld()) {
                        restoreOldCodes();
                    } else {
                        setDefaultCode();
                    }
                }
            }
            getCurrentEntity().setCodeAutogenerated(codeAutogenerated);
        }
    }

    public void setOldCode(String oldCode) {
        this.oldCode = oldCode;
    }

    public String getOldCode() {
        return oldCode;
    }

    public void setGenerateCodeOld(Boolean generateCodeOld) {
        this.generateCodeOld = generateCodeOld;
    }

    public Boolean isGenerateCodeOld() {
        return generateCodeOld;
    }

    public IEntitySequenceDAO getEntitySequenceDAO() {
        return entitySequenceDAO;
    }

}
